#ifndef DEBUG_H
#define DEBUG_H

#include "visitor.h"
#include <iostream>
#include <string>

/// Reprint the source structure using the info from AST
class SourcePrinter: public Visitor{
public:
    virtual void visitVariableExpr(VariableExpr& expr);
    virtual void visitBinaryExpr(BinaryExpr& expr);

    virtual void visitVariableDeclare(VariableDeclareStatement& stmt);
    virtual void visitAssignment(AssignmentStatement& stmt);
};

/// Generate source file for graphviz
class GraphPrinter{
private:
    std::ostream    &os;

    int tabs;
    // the node's prefix string
    std::string PRE;

    void    indent();
public:
    GraphPrinter(std::ostream &stream):os(stream),tabs(4){};
    void    beginGraph(std::string attrs[] = 0,int attrNum = 0);
    void    endGraph();
    void    beginSubgraph(std::string name,std::string attrs[] = 0,int attrNum = 0);
    void    endSubgraph();
    void    newNode(int index,std::string &label);
    void    newLine(int fromIndex,int toIndex);
    void    printLine(std::string str);
};

// TODO: this logprinter is ugly implemented
/// Source level printer
class LogPrinter{
private:
    bool    debug;
    std::ostream &stream;
public:
    LogPrinter(std::ostream &s = std::cout):stream(s),debug(true){};
    void    setDebug(bool dbg){debug = dbg;};
    bool    getDebug(){return   debug;};

    template<typename T>
    LogPrinter& operator <<(T s){
        if(debug){
            stream<<s;
        }
        return *this;
    }

    std::ostream&   getStream(){return  stream;};
};

/// deal with the std::endl
LogPrinter& operator <<(LogPrinter& log,
        std::basic_ostream<char,std::char_traits<char> >&
        (*op)(std::basic_ostream<char,std::char_traits<char> > &));

#endif

